package com.lfy.kcat.user.controller;

import com.lfy.kcat.user.template.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Redis 自增测试
 * @author leifengyang
 * @version 1.0
 * @date 2025/9/19 16:29
 * @description:
 */
@Slf4j
@RequestMapping("/api")
@RestController // spring组件单例
public class RedisIncrController {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    RedisService redisService;

    private static final String LOCK_KEY = "lockhahaabc";


    @GetMapping("/incr")
    public String incr2() throws InterruptedException {


        /**
         * 只写了一种最简的锁； 锁
         * 1. 可重入锁？ 实现可重入锁逻辑
         * 2. 公平锁？ 实现公平锁逻辑
         * 3. 非公平锁？ 实现非公平锁逻辑
         * 4. 自旋锁：
         * 5. 分段锁： 实现分段锁逻辑
         * 6. 读写锁： 实现读写锁逻辑
         * 7. 排他锁/共享锁；
         *    写锁：排它锁
         *    读锁：共享锁
         * 8. 乐观锁： 上来不加锁，  version 版本变化（CAS 乐观锁原理）
         * 9、 悲观锁： 上来就要加锁
         * 10. xxx
         *
         * Redisson： 分布式锁的全功能实现; 使用
         */


        // this 对象头  mark word  锁字段：  001: 无所  101：偏向锁  100： 轻量级锁  110： 重量级锁



        //断电；阻塞式 //原理
        String tokenValue = redisService.lock(LOCK_KEY);

        //走到下边，说明占坑成功，抢到锁了
//        redisTemplate.expire(LOCK_KEY,30, TimeUnit.SECONDS);

        //起一个后台线程，伴随线程； 看门狗机制
        Thread thread = new Thread(()->{
            //每等 1/3 锁时间，就续期一次
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(10);
                    //续期； 定时器； 喂狗
                    redisTemplate.expire(LOCK_KEY,30, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.setDaemon(true);
        thread.start();


        //1、获取当前值； 很多人可能执行到这一步
        String string = redisTemplate.opsForValue().get("hello:count");
        //2、加一操作
        int i = Integer.parseInt(string) + 1;
        //3、保存到redis
        redisTemplate.opsForValue().set("hello:count",i+"");


        //2、执行完毕，释放锁； 直接删，可能导致删除别人的锁
        //删除自己的锁。只需要对比 redis 中当前锁的值，是不是我当时保存的锁的值
//        String value = redisTemplate.opsForValue().get(LOCK_KEY);
//        if(token.equals(value)){
//            //判断是自己的锁再删除
//            //获取锁值 + 对比锁值 + 删除锁  = 解锁：原子操作
//            redisTemplate.delete(LOCK_KEY);
//        }

        redisService.unlock(LOCK_KEY,tokenValue);


        return "ok";
    }


    public String incr(){

        //++操作都不是原子操作；
        //jvm：堆、栈、方法区
        synchronized (RedisIncrController.class){
            //1、获取当前值； 很多人可能执行到这一步
            String string = redisTemplate.opsForValue().get("hello:count");

            //2、加一操作
            int i = Integer.parseInt(string) + 1;

            //3、保存到redis
            redisTemplate.opsForValue().set("hello:count",i+"");


        }

        return "ok";

    }
}
